using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace MoEngine
{
    public class WindowEventArgs : EventArgs
    {
        public WindowBase Window;
    }

    public class WindowCollection<T> : ICollection<T> where T : WindowBase
    {
        protected List<T> m_Windows = new List<T>();
        protected T[] m_CachedList;

        protected bool m_bLayerDirty = true;
        protected bool m_bCachedListDirty = true;

        protected static int CompareLayer(T a, T b)
        {
            return a.Layer.CompareTo(b.Layer);
        }

        protected void VerifyLayer()
        {
            if (m_bLayerDirty)
            {
                m_Windows.Sort(CompareLayer);
                m_bLayerDirty = false;
            }
        }

        protected void VerifyCachedList()
        {
            if (m_bCachedListDirty)
            {
                m_CachedList = new T[m_Windows.Count];
                m_Windows.CopyTo(m_CachedList);
                m_bCachedListDirty = false;
            }
        }

        public IEnumerable<T> LayeredList
        {
            get
            {
                VerifyLayer();
                VerifyCachedList();
                return m_CachedList;
            }
        }

        public IEnumerable<T> ReversedLayeredList
        {
            get
            {
                VerifyLayer();
                VerifyCachedList();
                for (int i = m_CachedList.Length - 1; i >= 0; i--)
                    yield return m_CachedList[i];
            }
        }

        public void UpdateAll(GameTime appTime)
        {
            foreach (T window in LayeredList)
            {
                window.Update(appTime);
            }
        }

        public void DrawAll(GameTime appTime)
        {
            foreach (T window in LayeredList)
            {
                window.Draw(appTime);
            }
        }

        public void HandleMouseInput(MouseEventType evtType, MouseButtons button, Point mousePos, InputEventArgs evtArgs)
        {
            foreach (T window in ReversedLayeredList)
            {
                if (window.HandleMouseInput(evtType, button, mousePos, evtArgs))
                    break;
            }
        }

        public event EventHandler<WindowEventArgs> WindowAdded;

        #region ICollection<T> Members
        public void Add(T item)
        {
            m_Windows.Add(item);

            // on window added
            // if item does not specify layer, give layer as its index
            if (item.Layer == 0)
                item.Layer = m_Windows.Count - 1;
            item.LayerChanged += new EventHandler(OnItemLayerChanged);
            m_bLayerDirty = true;
            m_bCachedListDirty = true;

            if (WindowAdded != null)
            {
                WindowEventArgs args = new WindowEventArgs();
                args.Window = item;
                WindowAdded(this, args);
            }
        }

        void OnItemLayerChanged(object sender, EventArgs e)
        {
            m_bLayerDirty = true;
        }

        public void Clear()
        {
            while (m_Windows.Count > 0)
            {
                Remove(m_Windows[0]);
            }
        }

        public bool Contains(T item)
        {
            return m_Windows.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            m_Windows.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return m_Windows.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(T item)
        {
            if (m_Windows.Remove(item))
            {
                item.LayerChanged -= OnItemLayerChanged;
                m_bCachedListDirty = true;
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return m_Windows.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
}
